#!/usr/bin/env bash
#------------------------{ Dev info }-----------------------------------------------------------------------------------
# Created by: Ivan Marov <ie.marov@gmail.com>
# Source: https://github.com/vaniacer/piu-piu-SH                         ░ ░ ░░░ ░ ░░ ░░░▒ ▒▒▒░░░ ░░ ░░ ░ ░
#--------------------------------------------------------------------+ ░   ░░░░ ░░░░▒▒▒▒ ▒▒▒▓ ▓▓▓▒▒▒▒▒▒▒░░░░ ░░░░ ░ ░ ░
# Color picker, usage: printf $BLD$CUR$RED$BBLU'Hello World!'$DEF    |   ░
#-------------------------+--------------------------------+---------+        ░   ░░░ ░░     ░  ░░      ░░  ░░ ░
#       Text color        |       Background color         |         |      ░   ░  ▒██████ ░▒██████ ▒██░  ▒██       ░
#-----------+-------------+--------------+-----------------+         |░       ░ ░░▒▓██ ▒▓██ ▓▓▓██▓ ▒▓██ ░▒▓██░░ ░
# Base color|Lighter shade| Base color   | Lighter shade   |         |     ░ ░ ░░▒▓██ ▒▓██ ▒▒▒▓██ ░▒▓██░ ▒▓██░
#-----------+-------------+--------------+-----------------+         |  ░ ░      ▒▓██████░ ░▒▓██ ░▒▓██ ░▒▓██░░ ░ ░
BLK='\e[30m'; blk='\e[90m'; BBLK='\e[40m'; bblk='\e[100m' #| Black   |       ░  ▒▓██▓▓▓▓  ░ ▒▓██░ ▒▓██░░▒▓██ ░     ░ ░
RED='\e[31m'; red='\e[91m'; BRED='\e[41m'; bred='\e[101m' #| Red     |        ▒▓████▒▒▒░ ░ ▓██████ ▒▓██████░░ ░
GRN='\e[32m'; grn='\e[92m'; BGRN='\e[42m'; bgrn='\e[102m' #| Green   |     ░ ░▒▓▓▓▓ ░ ░░▒▓▓▓▓▓▓ ░ ▒▓▓▓▓▓░
YLW='\e[33m'; ylw='\e[93m'; BYLW='\e[43m'; bylw='\e[103m' #| Yellow  |      ░ ▒▒ ░ ░ ░ ░▒▒▒▒▒▒ ░ ░░▒▒▒▒░  ░
BLU='\e[34m'; blu='\e[94m'; BBLU='\e[44m'; bblu='\e[104m' #| Blue    |  ░ ░                                      ░     ░
MGN='\e[35m'; mgn='\e[95m'; BMGN='\e[45m'; bmgn='\e[105m' #| Magenta |░                      ░░ ▒▒███░              ░
CYN='\e[36m'; cyn='\e[96m'; BCYN='\e[46m'; bcyn='\e[106m' #| Cyan    |     ░ ░ ░        ░░░ ▒████ ▒▓███░             ░
WHT='\e[37m'; wht='\e[97m'; BWHT='\e[47m'; bwht='\e[107m' #| White   |  ░ ░ ░        ░ ▒████▒▓▓▓▓ ░░▒▓▓███ ░░ ░
#-------------------------{ Effects }----------------------+---------+             ░ ▒▓▓▓▓ ▒████░▒▓███░░
DEF='\e[0m'   #Default color and effects                             |              ▒ ▒▒  ▒▓▓▓▓▒▓███░              ░
BLD='\e[1m'   #Bold\brighter                                         |     ░ ░         ░░░ ▒▒▒ ░░▒▒░
DIM='\e[2m'   #Dim\darker                                            |░ ░
CUR='\e[3m'   #Italic font                                           |          ░   ░░░ ░░     ░  ░░      ░░  ░░ ░
UND='\e[4m'   #Underline                                             |        ░   ░  ▒██████ ░▒██████ ▒██░  ▒██        ░
INV='\e[7m'   #Inverted                                              |   ░ ░    ░ ░░▒▓██ ▒▓██ ▓▓▓██▓ ▒▓██ ░▒▓██░░ ░
COF='\e[?25l' #Cursor Off                                            |       ░ ░ ░░▒▓██ ▒▓██ ▒▒▒▓██ ░▒▓██░ ▒▓██░    ░
CON='\e[?25h' #Cursor On                                             |             ▒▓██████░ ░▒▓██ ░▒▓██ ░▒▓██░░ ░ ░
#------------------------{ Functions }-------------------------------+░        ░  ▒▓██▓▓▓▓  ░ ▒▓██░ ▒▓██░░▒▓██ ░
# Text positioning, usage: XY 10 10 'Hello World!'                   |          ▒▓████▒▒▒░ ░ ▓██████ ▒▓██████░░ ░
XY () { printf "\e[$2;${1}H$3"; }                                   #|       ░ ░▒▓▓▓▓ ░ ░░▒▓▓▓▓▓▓ ░ ▒▓▓▓▓▓░
# Print line, usage: line - 10 | line -= 20 | line 'Hello World!' 20 |  ░     ░ ▒▒ ░ ░ ░ ░▒▒▒▒▒▒ ░ ░░▒▒▒▒░  ░       ░
line () { printf -v _L %$2s; printf -- "${_L// /$1}"; }             #|
# Create sequence like {0..(X-1)}                                    | ░ ░ ░ ░░░░░░▒▒▒▒ ▒▒▒▓ ▓▓▓▒▒▒▒▒░░░░░░ ░ ░ ░ ░ ░
que () { printf -v _N %$1s; _N=(${_N// / 1}); printf "${!_N[*]}"; } #|    ░ ░ ░░░ ░ ░░ ░░░▒ ▒▒▒░░░░░░░ ░ ░
#--------------------{ check bash version }--------------------------+--------------------------------------------------
tversion="4.2"                                          # needed  bash version
cversion="${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"      # current bash version
gawk '{if($1>$2){exit 1}}' <<< "$tversion $cversion" || {
    printf "\nYour BASH is too short!) $BLD$tversion+$DEF required to run this game, your is - $BLD$BASH_VERSION$DEF\n"
    exit 1
} #--{ Start opt }--------------------------------------{ description  }---------------------{ def. values }------------
  background=true                                       # background objects visibility             (true)
    storyspd=0.05                                       # story texting speed                       (0.05)
    bossborn=                                           # boss starter
    tillboss=100                                        # frags needed to fight with boss           (100)
     version='₁․₁'                                      # game version in small digits ₀₁₂₃₄₅₆₇₈₉․
     bhealth=100                                        # boss' health                              (100)
     showfps=true                                       # show FPS counter if set                   (true)
     enumber=0                                          # enemies counter                           (0)
     bonuses=("ammo" "life" "ammo" "gunup" "ammo")      # bonuses, more ammo, less life ang gun power ups
       enmax=100                                        # max number of enemies                     (10)
       crate=0                                          # crate drop                                (0)
       frags=0                                          # hero1 frags counter                       (0)
        life=3                                          # hero1 life counter                        (3)
        ammo=100                                        # hero1 ammo counter                        (100)
         DHC=$BLK                                       # default hero color                        ($BLK)
         DSC=$RED                                       # default symbol color                      ($RED)
         rnd=10                                         # random seed 4 bonuses                     (10)
         DHS='★'                                        # default symbol                            (★)
         spd=0.0001                                     # game\read speed                           (0.0001)
         MSN=1111                                       # messenger randomizer                      (1111)
         HOU=1111                                       # houses randomizer                         (1111)
          ad='Die alien scum!'                          # ad plane message                          'Die alien scum!'
           G=1                                          # gun                                       (1)(max 5)
read year month day dow < <(LANG=C date +'%Y %m %d %a') # get year, month, day and day of week at once
#----{ Multipleyer config }-----------------------------{ description  }---------------------{ def. values }------------
      frags2=0                                          # hero2 frags counter                       (0)
       life2=3                                          # hero2 life counter                        (3)
       ammo2=100                                        # hero2 ammo counter                        (100)
          G2=1                                          # hero2 gun                                 (1)(max 5)
       caddr=( $(hostname -I) )
       saddr=
       sport=54321
       cport=54322

[[ -e ~/.piuconf ]] && . ~/.piuconf
. ./functions #_FUNCTIONS_
. ./messages  #_MESSAGES_
. ./sprites   #_SPRITES_
#======================================{ Main game loop single or server mode }=========================================
game () {
    while true; do
        #-{ Empty screen, print game status and FPS }--------------------------
        screen=; status; [[ $showfps ]] && fps_counter
        #-{ Add background }---------------------------------------------------
        [[ $background ]] && add_backgound birds msngr clouds houses trees moving_land
        #-{ Move bitplans }----------------------------------------------------
        BP1=("${BP1[@]}"); for i in ${!BP1[@]}; { OI=(${BP1[i]}); print_sprite; } # small(far) background objects
        BP2=("${BP2[@]}"); for i in ${!BP2[@]}; { OI=(${BP2[i]}); print_sprite; } # medium background objects
        PIU=("${PIU[@]}"); for i in ${!PIU[@]}; { OI=(${PIU[i]}); print_sprite; } # heroes fire
        HER=("${HER[@]}"); for i in ${!HER[@]}; { OI=(${HER[i]}); print_sprite; } # heroes
        ENM=("${ENM[@]}"); for i in ${!ENM[@]}; { OI=(${ENM[i]}); print_sprite; } # enemies
        BP3=("${BP3[@]}"); for i in ${!BP3[@]}; { OI=(${BP3[i]}); print_sprite; } # big(closer) background objects
        #-{ BOSS }-------------------------------------------------------------
        if [[ $[frags+frags2] -ge $tillboss && $type != duel ]]; then # add boss object
            [[ $bossborn ]] || { ENM+=("boss $endx $halfy 6 14 0 0 1 0 $[RANDOM%3] 3 20 10"); bossborn=true; }
            boss_health # Print boss' health bar
            #-{ Add aliens }---------------------------------------------------
            [[ $bhealth -gt 0 ]] && add_enm $EX $EY 5 # aliens come out from boss
        else                                          #
            add_enm $endx $[4+RANDOM%enmyendy]        # aliens come out from edge
        fi
        #-{ Print everything }-------------------------------------------------
        printf "$screen"
        #-{ Check the end and send data to client }----------------------------
        case $game$type in
              *team) [[ ${HER[@]} ]] || the_end=lose;;&
              *duel) [[ ${HER[1]} ]] || if [[ $life -gt 0 ]]; then listener; sender $caddr $cport lose; mess win
                                                              else listener; sender $caddr $cport win ; mess lose; fi;;&
            server*) listener; sender $caddr $cport "$screen";;
        esac
        if [[ $the_end ]]; then
            case $game in 'server') listener; sender $caddr $cport $the_end;; esac
            mess $the_end; [[ $type != duel ]] && starship_intro starship
        fi
    done
}
#=========================================={ Client mode game loop }====================================================
game_client () {
    while true; do
        read_input
        sender $saddr $sport $input
        screen=$(nc -l -p $cport 2>/dev/null)
        case $screen in
             'win' ) mess   "$screen"; [[ $type != duel ]] && starship_intro starship;;
             'lose') mess   "$screen";;
             *     ) printf "$screen";;
        esac
    done
}
#============================================={ Starship intro }========================================================
starship_intro () {
    [[ $1 =~ starship ]] || return
    time_to_start=$((SECONDS+10))
    BP1=("Sun $Sunsendx 1 9 18 0 7 1 20 0 2") BP2=() BP3=() BP4=()
    ad_new= ad='Got a ticket to Mars?'; ad_plane_text; fill_screen; cursor off
    T1=($[halfx-8] $[halfx-15] $[halfx-18] $[endx-5] $[endx-9]  $[endx-15] $[endx-17] $[endx-25] $[endx-40] 3 7 11 15 20)
    T2=($[endx-7]  $[endx-11]  $[endx-35] 5 17 23)
    T3=($[endx-8]  $[endx-25]  4 23)
       # reserved for burning # type      $OX         $OY      $OH $OW $SC $SM $CS $CL $AS $AL
        BP2+=('' '' ''); BP2+=("windsock  $[halfx-17] $[endy-4] 2   8   0   0   1   7   0   2")    # windsock
                         BP2+=("starship   $halfx      $endy    10  7   0   10  10  10  0   5")    # starship
                         BP3+=("startable $[halfx-4]  $[endy-2] 8   15  0   50  10  10  0   1")    # startable
                         BP4+=("lift      $[halfx+8]  $[endy-4] 1   3   0   30  1   1   0   4")    # lift
    for i in ${T1[@]}; { BP1+=("tree1      $i         $tre1endy 4   2   0  -1   1   5   0   0"); } # Plant
    for i in ${T2[@]}; { BP2+=("tree2      $i         $tre2endy 6   5   0  -1   1   5   0   0"); } # some
    for i in ${T3[@]}; { BP3+=("tree3      $i         $tre3endy 9   9   0  -1   1   9   0   0"); } # trees
    while true; do
        #-{ Empty screen, print game status adnd FPS }-------------------------
        screen=; [[ $showfps ]] && fps_counter; ((SECONDS==time_to_start)) && lift=up
        # Start the engine (add exhaust sprite)
        [[   $ex1   ]] && { BP2+=( "exhaust $[halfx-31] $[endy-3] 4 33 0 7 1 33 0 9"); ex1=; }
        #-{ Add background }---------------------------------------------------
        [[ $background ]] && add_backgound birds msngr clouds land
        #-{ Move bitplans }----------------------------------------------------
        BP1=("${BP1[@]}"); for i in ${!BP1[@]}; { OI=(${BP1[i]}); print_sprite; } # small(far) background objects
        BP2=("${BP2[@]}"); for i in ${!BP2[@]}; { OI=(${BP2[i]}); print_sprite; } # medium background objects
        BP3=("${BP3[@]}"); for i in ${!BP3[@]}; { OI=(${BP3[i]}); print_sprite; } # big(closer) background objects
        BP4=("${BP4[@]}"); for i in ${!BP4[@]}; { OI=(${BP4[i]}); print_sprite; } # lift
        #-{ Print everything }-------------------------------------------------
        printf "$screen"
    done
    exit
}
#============================================{ Initialisation }=========================================================
BP1=("Sun $Sunsendx 1 9 18 0 7 1 20 0 2")                   # Sun
H1X=1 H1Y=2 HER=("hero1 $H1X $H1Y 6 16 0 0 1 15 0 3 15 10") # Hero
trap : ALRM; trap bye INT TERM SIGINT SIGTERM EXIT
clear; starship_intro $1; mess "help"; sleep 2
clear; intro; menu
clear; fill_screen
cursor off
#-{ If server }---------------------------------------------------------------------------------------------------------
case $game:$type in
    server:team) H2X=1         H2Y=$[halfy-2];;&
    server:duel) H2X=$heroendx H2Y=$[halfy-2] H1Y=$[halfy-2] enmax=0; ad_plane_text;;&
    server:*   ) XY 2 1 $SKY$RED"Server mode. Waiting for client..."
                 HER+=("hero2 $H2X $H2Y 6 16 0 0 1 15 0 3 15 10")
                 clnt=( $(nc -l -p $sport) )
                 caddr=${clnt[0]}
                 cport=${clnt[1]}
                 H2C=${clnt[2]:-$DHC}
                 H2S=${clnt[3]:-$DHS}
                 S2C=${clnt[4]:-$DSC};;
#-{ If client }---------------------------------------------------------------------------------------------------------
    client:*   ) XY 2 1 $SKY$RED"Client mode. Waiting for server..."
                 sender $saddr $sport "${caddr[0]} $cport $H1C $H1S $S1C"
                 game_client;;
esac
game
